package com.gkzf.ai.module.crm.service.creditreportsimple.app;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gkzf.ai.framework.common.exception.ServerException;
import com.gkzf.ai.framework.common.exception.ServiceException;
import com.gkzf.ai.framework.common.pojo.PageResult;
import com.gkzf.ai.framework.common.util.object.BeanUtils;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.LiabilityVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.OverdueRecordVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.QueryLimitVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportdetails.CreditReportDetailsSaveReqVO;
import com.gkzf.ai.module.crm.controller.admin.simpleCredit.vo.CreditReportSimpleRespVO;
import com.gkzf.ai.module.crm.controller.admin.simpleCredit.vo.CreditReportSimpleSaveReqVO;
import com.gkzf.ai.module.crm.controller.app.simpleCredit.vo.condition.UserAdmittanceConditionSaveReqVO;
import com.gkzf.ai.module.crm.controller.app.simpleCredit.vo.simple.SimplePageReqVO;
import com.gkzf.ai.module.crm.dal.dataobject.creditReport.CreditReportDO;
import com.gkzf.ai.module.crm.dal.dataobject.creditreportsimple.CreditReportSimpleCreditCardDO;
import com.gkzf.ai.module.crm.dal.dataobject.creditreportsimple.CreditReportSimpleDO;
import com.gkzf.ai.module.crm.dal.dataobject.creditreportsimple.CreditReportSimpleLoanDO;
import com.gkzf.ai.module.crm.dal.mysql.creditreportsimple.CreditReportSimpleMapper;
import com.gkzf.ai.module.crm.enums.ModelAnalysisDictEnum;
import com.gkzf.ai.module.crm.service.creditReport.CreditReportAdmittanceConditionService;
import com.gkzf.ai.module.crm.service.creditReport.CreditReportService;
import com.gkzf.ai.module.crm.threads.CreditReportThreadsPost;
import com.gkzf.ai.module.crm.util.packaging.CalculationQueryRecord;
import com.gkzf.ai.module.system.api.dept.DeptApi;
import com.gkzf.ai.module.system.api.dict.DictDataApi;
import com.gkzf.ai.module.system.api.dict.dto.DictDataRespDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

import static com.gkzf.ai.module.crm.enums.ModelAnalysisDictEnum.*;
import static com.gkzf.ai.module.crm.util.AnalysisJsonObjectUtils.*;
import static com.gkzf.ai.module.crm.util.AnalysisJsonObjectUtils.LOANS;
import static com.gkzf.ai.module.crm.util.assembly.AssemblyCreditReportDetails.*;
import static com.gkzf.ai.module.crm.util.simpleCredit.SimpleCreditExtract.*;

/**
 * CRM 征信报告简版 Service 实现类
 *
 * @author 国科智飞
 */
@Slf4j
@Service
@Validated
public class AppCreditReportSimpleServiceImpl implements AppCreditReportSimpleService {

    @Resource
    private CreditReportSimpleMapper creditReportSimpleMapper;

    @Resource
    private AppCreditReportSimpleCreditCardService appCreditReportSimpleCreditCardService;

    @Resource
    private CreditReportAdmittanceConditionService creditReportAdmittanceConditionService;

    @Resource
    private AppUserAdmittanceConditionService updateUserAdmittanceHouse;

    @Resource
    private AppCreditReportSimpleLoanService appCreditReportSimpleLoanService;


    @Resource
    private CreditReportService creditReportService;

    @Resource
    private DeptApi deptApi;

    @Resource
    private DictDataApi dictDataApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Async
    public void createCreditReportSimple(CreditReportSimpleSaveReqVO simpleSaveReqVO,CreditReportSimpleDO creditReportSimple,CreditReportDO creditReportDO) {
        log.info("开始解析简版征信报告...");
        RetryTemplate retryTemplate = new RetryTemplate();
        // 4 设置重试策略 最大重试 3 次，只重试 RuntimeException
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(100, Collections.singletonMap(ServerException.class, true));
        retryTemplate.setRetryPolicy(retryPolicy);
        // 5 设置退避策略
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        // 延迟 1 秒
        backOffPolicy.setBackOffPeriod(1000);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        // 记录白户
        AtomicInteger atomicInteger = new AtomicInteger(2);
        log.info("定时策略创建完成...");
        DictDataRespDTO appCreditReport = dictDataApi.parseDictData(ModelAnalysisDictEnum.DICT_TYPT.getCode(), ModelAnalysisDictEnum.APP_CREDIT_REPORT.getCode());
        Map<String, Object> reqMap = retryTemplate.execute(context -> {
            log.info("简版征信异步大模型解析征信报告，开始时间：{}", DateUtil.formatDateTime(new Date()));
            ExecutorService executor = Executors.newFixedThreadPool(8);
            Map<String, Object> map = new HashMap<>();
            try {
                Date date = new Date();
                // type 1 基础和个人查询记录
                CreditReportThreadsPost modelLoanObject = new CreditReportThreadsPost(appCreditReport.getValue()+"?input_url="+simpleSaveReqVO.getCreditReportUrl()+"&extract_type=1&app_id="+ModelAnalysisDictEnum.APP_ID.getCode());
                Future<String> basicSubmit = executor.submit(modelLoanObject);

                // type 2 机构查询记录
                CreditReportThreadsPost modelCreditCardObject = new CreditReportThreadsPost(appCreditReport.getValue()+"?input_url="+simpleSaveReqVO.getCreditReportUrl()+"&extract_type=2&app_id="+ModelAnalysisDictEnum.APP_ID.getCode());
                Future<String> querySubmit = executor.submit(modelCreditCardObject);

                // type 3 信用卡记录
                CreditReportThreadsPost queryObject = new CreditReportThreadsPost(appCreditReport.getValue()+"?input_url="+simpleSaveReqVO.getCreditReportUrl()+"&extract_type=3&app_id="+ModelAnalysisDictEnum.APP_ID.getCode());
                Future<String> creditSubmit = executor.submit(queryObject);

                // type 4 贷款记录
                CreditReportThreadsPost basicObject = new CreditReportThreadsPost(appCreditReport.getValue()+"?input_url="+simpleSaveReqVO.getCreditReportUrl()+"&extract_type=4&app_id="+ModelAnalysisDictEnum.APP_ID.getCode());
                Future<String> loanSubmit = executor.submit(basicObject);

                String basic = basicSubmit.get();
                map.put(KEY_BASIC, basic);
                creditReportDO.setBasic(basic);

                String queryRecord = querySubmit.get();
                map.put(KEY_QUERY_RECORD, queryRecord);
                creditReportDO.setCyclicOne(queryRecord);

                String creditCard = creditSubmit.get();
                map.put(KEY_MODEL_CREDIT_CARD, creditCard);
                creditReportDO.setCyclicTow(creditCard);

                String loan = loanSubmit.get();
                map.put(KEY_MODEL_LOAN, loan);
                creditReportDO.setCredit(loan);
                log.info("大模型计算时间:{}秒",DateUtil.between(date, new Date(), cn.hutool.core.date.DateUnit.SECOND));
                executor.shutdown(); //  必须关闭，否则程序不会退出
                return map;
            }catch (InterruptedException e) {
                // 正确处理中断异常，恢复线程中断状态
                Thread.currentThread().interrupt();
                log.error("征信报告解析任务被中断", e);
                throw new ServiceException(-1, "处理中断，请重试");
            }catch (Exception e){
                log.error("征信报告解析异常", e);
                throw new ServiceException(-1,"正在处理中，请稍后重试");
            }
        });
        try {
            List<CreditReportSimpleCreditCardDO> simpleCreditCardList = new ArrayList<>();
            List<CreditReportSimpleLoanDO> simpleLoanList = new ArrayList<>();
            List<Map<String, String>> queryRecordList = new ArrayList<>();
            conversion(reqMap, KEY_BASIC, loanInfo -> extract(loanInfo, atomicInteger, simpleSaveReqVO, queryRecordList, simpleCreditCardList, simpleLoanList));
            conversion(reqMap, KEY_QUERY_RECORD, loanInfo -> extract(loanInfo, atomicInteger, simpleSaveReqVO, queryRecordList, simpleCreditCardList, simpleLoanList));
            conversion(reqMap, KEY_MODEL_CREDIT_CARD, loanInfo -> extract(loanInfo, atomicInteger, simpleSaveReqVO, queryRecordList, simpleCreditCardList, simpleLoanList));
            conversion(reqMap, KEY_MODEL_LOAN, loanInfo -> extract(loanInfo, atomicInteger, simpleSaveReqVO, queryRecordList, simpleCreditCardList, simpleLoanList));
            // 信用贷款总额 取值：贷款余额➕信用卡已使用额度
            simpleSaveReqVO.setTotalLiabilities(simpleSaveReqVO.getLoanBalance().add(simpleSaveReqVO.getCreditCardUsedCredit()));
            // 逾期次数贷款合计账户数 取值：贷款账户数➕信用卡账户数
            simpleSaveReqVO.setOverdueSumAccount(simpleSaveReqVO.getOverdueLoanAccount() + simpleSaveReqVO.getOverdueCardAccount());
            // 逾期90天以上贷款合计账户数 取值：贷款账户数➕信用卡账户数
            simpleSaveReqVO.setOverdueSum90Account(simpleSaveReqVO.getOverdueLoan90Account() + simpleSaveReqVO.getOverdueCard90Account());
            /*
                根据查询记录json 解析查询记录
                解析出查询记录各个时间维度的值转换成json
             */
            List<DictDataRespDTO> queryLimitDictDataList = dictDataApi.getDictDataList(ModelAnalysisDictEnum.QUERY_RECORD_COLLECT.getCode());
            CalculationQueryRecord calculationQueryRecord = new CalculationQueryRecord(queryLimitDictDataList);
            CreditReportDetailsSaveReqVO detailsSaveReqVO = new CreditReportDetailsSaveReqVO();
            String extractQueryRecord = calculationQueryRecord.extractQueryRecord(queryRecordList, detailsSaveReqVO);
            simpleSaveReqVO.setQueryRecordCollect(extractQueryRecord);
            simpleSaveReqVO.setMostRecentQueryTime(detailsSaveReqVO.getMostRecentQueryTime());
            // 插入简版征信
            simpleSaveReqVO.setId(creditReportSimple.getId());
            BeanUtils.copyProperties(simpleSaveReqVO, creditReportSimple);
            creditReportSimple.setCreditReportWhiteType(atomicInteger.get());
            // 请求获取al分析结果
            String creditAnalysis = analysisCreditReport(simpleSaveReqVO);
            // 添加管理员ID为创建人 统一分配
            creditReportSimple.setCreditAnalysis(creditAnalysis);
            creditReportSimple.setDeptId(deptApi.getMaxDeptId());
            creditReportSimple.setIsAllocation(0);
            creditReportSimple.setStatus(1);
            creditReportSimpleMapper.updateById(creditReportSimple);
            UserAdmittanceConditionSaveReqVO conditionSaveReqVO = assemblyUserAdmittanceCondition(creditReportSimple, simpleCreditCardList, simpleLoanList);
            conditionSaveReqVO.setIdNumber(creditReportSimple.getIdNumber());
            conditionSaveReqVO.setUserOpenId(creditReportSimple.getUserOpenId());
            updateUserAdmittanceHouse.updateUserAdmittanceConditionXml(conditionSaveReqVO);
            // 插入逾期记录
            simpleCreditCardList.forEach(creditReportSimpleOverdue -> creditReportSimpleOverdue.setCreditReportSimpleId(creditReportSimple.getId()));
            simpleLoanList.forEach(creditReportSimpleOverdue -> creditReportSimpleOverdue.setCreditReportSimpleId(creditReportSimple.getId()));
            appCreditReportSimpleCreditCardService.createCreditReportSimpleOverdue(simpleCreditCardList);
            appCreditReportSimpleLoanService.createCreditReportSimpleOverdue(simpleLoanList);
            creditReportDO.setCreditBasicId(creditReportSimple.getId());
        }catch (Exception e){
            log.error("处理异常，请重试", e);
            creditReportSimple.setStatus(2);
            creditReportSimpleMapper.updateById(creditReportSimple);
            throw new ServiceException(-1, "处理异常，请重试");
        }finally {
            updateCreditReportSimple(creditReportDO);
        }
    }

    @Override
    public CreditReportSimpleDO createCreditReportSimple(CreditReportSimpleSaveReqVO createReqVO) {
        CreditReportSimpleDO creditReportDO = new CreditReportSimpleDO();
        BeanUtils.copyProperties(createReqVO, creditReportDO);
        creditReportDO.setStatus(0);
        creditReportSimpleMapper.insert(creditReportDO);
        return creditReportDO;
    }

    public UserAdmittanceConditionSaveReqVO assemblyUserAdmittanceCondition(CreditReportSimpleDO creditReportSimple,
                                                                                    List<CreditReportSimpleCreditCardDO> simpleCreditCardList,
                                                                                    List<CreditReportSimpleLoanDO> simpleLoanList) {
        /*
          组装 用户准入表数据
        */
        UserAdmittanceConditionSaveReqVO updateReqVO = new UserAdmittanceConditionSaveReqVO();
        // 五级分类
        updateReqVO.setCreditReportFiveLevel(getFiveLevel(simpleCreditCardList,simpleLoanList));
        // 年龄
        updateReqVO.setAge(creditReportSimple.getAge());
        // 性别
        updateReqVO.setGender(creditReportSimple.getGender());
        // 负债情况
        List<LiabilityVo> liabilityList = new ArrayList<>();
        for (int i = 1; i <= 6; i++){
            LiabilityVo liabilityVo = getLiabilityVo(creditReportSimple, i);
            liabilityList.add(liabilityVo);
        }
        updateReqVO.setCreditReportLiabilityJson(JSON.toJSONString(liabilityList.toString()));
        // 逾期json
        Map<String, List<OverdueRecordVo>> param = getListMap(creditReportSimple);
        updateReqVO.setCreditReportOverdueJson(JSON.toJSONString(JSON.toJSON(param)));
        // 查询记录
        updateReqVO.setCreditReportQueryJson(creditReportSimple.getQueryRecordCollect());
        // 白户
        updateReqVO.setCreditReportWhiteType(creditReportSimple.getCreditReportWhiteType());

        return updateReqVO;
    }

    /**
     * 组装征信详情拼接成字符串 ai解析成自然语言
     *
     * @param detailsDO 征信报告详情
     */
    public String analysisCreditReport(CreditReportSimpleSaveReqVO detailsDO) {
        // 征信解析的字段
        String creditAnalysis = assemblingPersonalCreditReportDetails(detailsDO);
        log.info("征信解析的字段:{}",creditAnalysis);
        DictDataRespDTO dictDataRespDTO = dictDataApi.parseDictData(DICT_TYPT.getCode(), ADMIN_DATA_ANALYZE.getCode());
        String creditAnalysisReq = HttpUtil.post(dictDataRespDTO.getValue() + "?user_data=" + creditAnalysis + "&app_id=" + APP_ID.getCode(), new LinkedHashMap<>());
        Map<String,Object> reqMap = JSON.parseObject(creditAnalysisReq,new TypeReference<>(){});
        if (reqMap.containsKey(RESULT)){
            if (null != detailsDO.getId()){
                detailsDO.setCreditAnalysis(reqMap.get("result").toString());
                creditReportSimpleMapper.updateById(BeanUtils.toBean(detailsDO, CreditReportSimpleDO.class));
            }
            return reqMap.get(RESULT).toString();
        }
        return "";
    }

    @Override
    public PageResult<CreditReportSimpleRespVO> getCreditReportSimplePage(SimplePageReqVO simplePageReqVO) {
        IPage<CreditReportSimpleRespVO> simplePage = creditReportSimpleMapper.selectAppPage(new Page<>(simplePageReqVO.getPageNo(), simplePageReqVO.getPageSize()), simplePageReqVO);
        return new PageResult<>(simplePage.getRecords(), simplePage.getTotal());
    }

    /**
     * 组装个人征信报告详情
     * @return 征信报告详情
     */
    public String assemblingPersonalCreditReportDetails(CreditReportSimpleSaveReqVO detailsDO){
        /*
           查询记录情况
         */
        StringBuilder queryRecord = new StringBuilder();
        creditReportAdmittanceConditionService.analysisQueryRecord(detailsDO.getQueryRecordCollect(),1, queryLimitVoList -> {
            for (QueryLimitVo queryLimitVo : queryLimitVoList) {
                queryRecord.append("近").append(queryLimitVo.getQueryLimitMonths()).append("个月").append(queryLimitVo.getQueryLimitMaxCount()).append("次").append(COMMA);
            }
        });

        StringBuilder details = new StringBuilder();
        details.append("负债总额:").append(detailsDO.getTotalLiabilities()).append("元")
                .append(COMMA).append("贷款余额:").append(Optional.ofNullable(detailsDO.getLoanBalance()).orElse(BigDecimal.ZERO)).append("元")
                .append(COMMA).append("信用卡已使用额度:").append(Optional.ofNullable(detailsDO.getCreditCardUsedCredit()).orElse(BigDecimal.ZERO)).append("元")
                .append(COMMA).append("信用卡当前使用率:").append(Optional.ofNullable(detailsDO.getCreditCardCurrentRate()).orElse(BigDecimal.ZERO)).append("%")
                .append(COMMA).append("贷款逾期数账户数:").append(Optional.ofNullable(detailsDO.getOverdueLoanAccount()).orElse(0)).append("个")
                .append(COMMA).append("信用卡逾期账户数 :").append(Optional.ofNullable(detailsDO.getOverdueCardAccount()).orElse(0)).append("个")
                .append(COMMA).append("非银行机构数 :").append(Optional.ofNullable(detailsDO.getNonBankingOrganizationAccount()).orElse(0)).append("个")
                .append(COMMA).append("贷款机构数:").append(Optional.of(detailsDO.getNonBankingOrganizationAccount()+detailsDO.getBankingOrganizationAccount()).orElse(0)).append("个").append(COMMA);

        if (StringUtils.isNotBlank(queryRecord)){
            details.append("机构查询记录情况:").append(queryRecord, 0, queryRecord.length() - 1);
        }else {
            details.append("机构查询记录情况:无");
        }
        return details.toString();

    }

    /**
     * 创建解析的征信记录 （用户核对）
     * @param creditReportDO 简版征信
     */
    public void updateCreditReportSimple(CreditReportDO creditReportDO) {
        creditReportService.createCreditReport(creditReportDO);
    }


    /**
     * 查询详情
     * @param id 简版ID
     * @return 详情对象
     */
    @Override
    public CreditReportSimpleRespVO getCreditReportSimple(Long id) {
        CreditReportSimpleDO creditReportSimpleDO = creditReportSimpleMapper.selectById(id);
        return BeanUtils.toBean(creditReportSimpleDO, CreditReportSimpleRespVO.class);
    }

    /**
     *  解析失败 重试一次
     * @param id 简版征信Id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void tryAgain(Long id) {
        CreditReportSimpleDO creditReportSimpleDO = creditReportSimpleMapper.selectById(id);
        CreditReportSimpleSaveReqVO creditReportSimpleSaveReqVO = BeanUtils.toBean(creditReportSimpleDO, CreditReportSimpleSaveReqVO.class);
        createCreditReportSimple(creditReportSimpleSaveReqVO,creditReportSimpleDO,new CreditReportDO());
    }


    /**
     *  修改解析状态
     * @param id 简版征信Id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id) {
        CreditReportSimpleDO creditReportSimpleDO = creditReportSimpleMapper.selectById(id);
        creditReportSimpleDO.setStatus(0);
        creditReportSimpleMapper.updateById(creditReportSimpleDO);
    }

    /**
     * 获取五级
     * @param simpleCreditCardList 信用卡列表
     * @param simpleLoanList 贷款列表
     * @return 五级分类
     */
    public static int getFiveLevel(List<CreditReportSimpleCreditCardDO> simpleCreditCardList,List<CreditReportSimpleLoanDO> simpleLoanList) {
        long countCred = simpleCreditCardList.stream().filter(item -> Objects.nonNull(item.getIsOverdue()) && item.getIsOverdue().equals("true")).count();
        long countLoan = simpleLoanList.stream().filter(item -> Objects.nonNull(item.getIsOverdue()) && item.getIsOverdue().equals("true")).count();
        if (countCred + countLoan > 0){
            return 1;
        }else {
            return 0;
        }
    }

    /**
     * 组装 用户逾期json 逾期记录
     * @param creditReportSimple 简版对象
     * @return map
     */
    private static Map<String, List<OverdueRecordVo>> getListMap(CreditReportSimpleDO creditReportSimple) {
        Map<String, List<OverdueRecordVo>> param = new HashMap<>();
        List<OverdueRecordVo> overdueCredRecordList = new ArrayList<>();
        OverdueRecordVo overdueRecordVo = new OverdueRecordVo();
        overdueRecordVo.setOverUeRecordMonths("60,"+ creditReportSimple.getOverdueCardAccount());
        overdueCredRecordList.add(overdueRecordVo);
        param.put(CREDITCARD,overdueCredRecordList);
        List<OverdueRecordVo> overdueLoanRecordList = new ArrayList<>();
        OverdueRecordVo overdueLoanRecordVo = new OverdueRecordVo();
        overdueLoanRecordVo.setOverUeRecordMonths("60,"+ creditReportSimple.getOverdueLoanAccount());
        overdueLoanRecordList.add(overdueLoanRecordVo);
        param.put(LOANS,overdueLoanRecordList);
        return param;
    }

    /**
     *  组装简版负债情况
     * @param creditReportSimple 简版对象
     * @param i type
     * @return LiabilityVo
     */
    private static LiabilityVo getLiabilityVo(CreditReportSimpleDO creditReportSimple, int i) {
        LiabilityVo liabilityVo = new LiabilityVo();
        switch (i) {
            case 1 -> {
                liabilityVo.setLiabilityRequirementType(i);
                liabilityVo.setLiabilityRequirementAmount(String.valueOf(creditReportSimple.getNonBankingOrganizationAccount()));
            }
            case 2 -> {
                liabilityVo.setLiabilityRequirementType(i);
                liabilityVo.setLiabilityRequirementAmount(String.valueOf(creditReportSimple.getNonBankingOrganizationMoney()));
            }
            case 3 -> {
                liabilityVo.setLiabilityRequirementType(i + 1);
                liabilityVo.setLiabilityRequirementAmount(String.valueOf(creditReportSimple.getCreditCardCurrentRate()));
            }
            default -> {
                liabilityVo.setLiabilityRequirementType(null);
                liabilityVo.setLiabilityRequirementAmount(null);
            }
        }
        return liabilityVo;
    }
}